package hirt;

import java.nio.ByteBuffer;
import java.util.Vector;

/**
 * Automobile extends from MoveableItem. It is one of the most prominent
 * extensions of Item. Automobile sub types and role id's signify which
 * responder department or class of car in the hirt simulation. Automobiles have
 * front wheels and thus they have their own angle associated with them.
 * Conditions are particularly important in the case of highway incidents.
 * Therefore, damage, moveability, and whether they are on fire are booleans.
 * All automobiles typically have lights, some automobiles have more light
 * states than others.
 * @author puzzud
 */
public class Automobile extends MoveableItem
{
    /**
     * Role id associated with this automobile.
     * (ie POLICE to a police car).
     */
    int roleId;

    /**
     * Angle (in degrees) of this automobile.
     */
    float wheelAngle;

    /**
     * Status of this light (specific to sub type).
     */
    int lightStatus;

    /**
     * Condition of whether this automoibile is damaged.
     */
    boolean damaged;

    /**
     * Condition of whether this automobile is moveable.
     */
    boolean moveable;

    /**
     * Condition of whether this automobile is on fire.
     */
    boolean onFire;

    Lane lane;
    int intendedSpeed;

    /**
     * Reference id of which automobile of sub type this is.
     * (ie Police Car #2).
     */
    int instance;

    /**
     * Automobile states.
     */
    public final static int STATE_PARKING = STATE_PLACING;
    public final static int STATE_PARKED = STATE_PLACED;
    public final static int STATE_ARRIVING = 3;
    public final static int STATE_LEAVING = 4;

    /**
     * Constructor that makes an appropriate automobile for the specified
     * role id.
     * @param roleId specified role for this automobile.
     */
    public Automobile( int roleId )
    {
        super();

        setRole( roleId );
        setWheelAngle( 0.0f );
        setLightStatus( 0 );
        setDefaultConditions();
        setLane( null );
        setInstance( 0 );
        
        setType( Role.getRoleVehicleName( roleId ) );

        // Determine what type of car.
        if( ( roleId == Role.NONE ) || ( roleId == Role.VICTIM ) )
        {
            createStandardCar( roleId );
        }
        else
        {
            createResponderCar( roleId );
        }
    }

    /**
     * Builds an Item from a byte stream, presumably created by an item across the network
     * this item should be identical to that one
     * @param bytes
     * @param items: Master Item List used to build the Item
     */
    public Automobile(ByteBuffer bytes, Vector<Item> items)
    {
        fromBytes(bytes,items);
    }

    /**
     * Builds an Item from a save string, presumably created by an item when saving to a file
     * this item should be identical to that one
     * @param saveString
     * @param items: Master Item List used to build the Item
     */
    public Automobile(String text, Vector<Item> items)
    {
        fromSaveString(text,items);
    }

    /**
     * Default conditions for this automobile.
     */
    private void setDefaultConditions()
    {
        setDamage(false);
        setMoveable(true);
        setFire(false);
    }

    public void setDamage(boolean value)
    {
        this.damaged = value;
    }

    private boolean getDamaged()
    {
        return damaged;
    }

    private boolean getMoveable()
    {
        return moveable;
    }

    private boolean getFire()
    {
        return onFire;
    }

    public void setMoveable(boolean value)
    {
        this.moveable = value;
    }

    public void setFire(boolean value)
    {
        this.onFire = value;
    }

    /**
     * Method outfits this automobile to have the properties of the autombile
     * based on the specified role id. However, internal logic only handles
     * non responder type roles, such as VICTIM.
     * @param roleId specified role associated for this type of automobile.
     */
    private void createStandardCar( int roleId )
    {
        setDefaultConditions();

        if( roleId < 0 )
        {
            //System.out.println( "Automobile.createStandardCar(): Not set to work with Role.NONE" );
            roleId = Role.VICTIM;   // NOTE: For the time being, make this NONE a VICTIM.
        }

        this.setWidth( ServerConstants.ITEM2D_DIMENSIONS[roleId].x );
        this.setHeight( ServerConstants.ITEM2D_DIMENSIONS[roleId].y );
    }

    /**
     * Method outfits this automobile to have the properties of a responder
     * automobile specified by role id.
     * @param roleId specified responder role id.
     */
    private void createResponderCar( int roleId )
    {
        setDefaultConditions();

        this.setWidth( ServerConstants.ITEM2D_DIMENSIONS[roleId].x );
        this.setHeight( ServerConstants.ITEM2D_DIMENSIONS[roleId].y );
    }


    public float getWheelAngle()
    {
        return( wheelAngle );
    }

    public void setWheelAngle( float wheelAngle )
    {
        this.wheelAngle = wheelAngle;
    }

    public int getLightStatus()
    {
        return( lightStatus );
    }

    public void setLightStatus( int lightStatus )
    {
        this.lightStatus = lightStatus;
    }

    public boolean isMoveable()
    {
        return getMoveable();
    }

    public boolean isOnFire()
    {
        return getFire();
    }

    public boolean isDamaged()
    {
        return getDamaged();
    }

    public Lane getLane()
    {
        return( lane );
    }

    public void setLane( Lane lane )
    {
        this.lane = lane;
    }

    public int getIntendedSpeed()
    {
        return( intendedSpeed );
    }

    public void setIntendedSpeed( int intendedSpeed )
    {
        this.intendedSpeed = intendedSpeed;
    }

    void action()
    {

    }

    public void setInstance(int instance)
    {
        if (instance >= 0)
        {
            this.instance = instance;
        }
    }

    public int getInstance()
    {
        return( instance );
    }

    public int getRoleId()
    {
        return( roleId );
    }

    public void setRole( int roleId )
    {
        this.roleId = roleId;
    }

    @Override
    public String toString()
    {
        return Role.getName(roleId) + " " + type + " #" + instance;
    }

    /**
     * Returns a ByteBuffer representation of this Item
     * Used to send items over the network
     * @return ByteBuffer
     */
    @Override
     public ByteBuffer toByte()
    {
        ByteBuffer buf = super.toByte();
        buf.putInt(roleId);
        buf.putFloat(wheelAngle);
        buf.putInt(lightStatus);
        buf.put(ByteChanger.booleanToByte(damaged));
        buf.put(ByteChanger.booleanToByte(moveable));
        buf.put(ByteChanger.booleanToByte(onFire));
        buf.putInt(intendedSpeed);
        buf.putInt(instance);
        return buf;

    }

    /**
     * Returns a String representation of this Item
     * Used to save this item to a file
     * @return Save String
     */
    @Override
    public String toSaveString()
    {
        String text = super.toSaveString();
        text += roleId + "\t";
        text += wheelAngle + "\t";
        text += lightStatus + "\t";
        text += damaged + "\t";
        text += moveable + "\t";
        text += onFire + "\t";
        text += intendedSpeed + "\t";
        text += instance + "\t";
        return text;
    }

    /**
     * Builds an Item from a byte stream, presumably created by an item across the network
     * this item should be identical to that one
     * @param bytes
     * @param items: Master Item List used to build the action
     * @return what's left of the parem bytes after this method is completes
     */
    @Override
    protected ByteBuffer fromBytes(ByteBuffer bytes, Vector<Item> items)
    {
        bytes = super.fromBytes(bytes, items);
        roleId = bytes.getInt(0);
        wheelAngle = bytes.getFloat(4);
        lightStatus = bytes.getInt(8);
        damaged = ByteChanger.getBoolean(bytes, 12);
        moveable = ByteChanger.getBoolean(bytes, 13);
        onFire = ByteChanger.getBoolean(bytes, 14);
        intendedSpeed = bytes.getInt(15);
        instance = bytes.getInt(19);
        try {
            bytes = ByteChanger.truncate(bytes, 23);
        } catch (Exception ex) {

        }
        return bytes;
    }



    /**
     * Builds an Item from a save string, presumably read from a save
     * this item should be identical to the one saved in the file
     * @param save string
     * @param items: Master Item List used to build the action
     * @return what's left of the parem SaveString after this methods completes
     */
    @Override
    protected String fromSaveString(String text, Vector<Item> items)
    {
        text = super.fromSaveString(text, items);
        String substring = ByteChanger.getNextValue(text);
        roleId = Integer.parseInt(substring);

        text = ByteChanger.incrementString(text);
        substring = ByteChanger.getNextValue(text);
        wheelAngle = Float.parseFloat(substring);

        text = ByteChanger.incrementString(text);
        substring = ByteChanger.getNextValue(text);
        lightStatus = Integer.parseInt(substring);

        text = ByteChanger.incrementString(text);
        substring = ByteChanger.getNextValue(text);
        damaged = Boolean.parseBoolean(substring);

        text = ByteChanger.incrementString(text);
        substring = ByteChanger.getNextValue(text);
        moveable = Boolean.parseBoolean(substring);

        text = ByteChanger.incrementString(text);
        substring = ByteChanger.getNextValue(text);
        onFire = Boolean.parseBoolean(substring);

        text = ByteChanger.incrementString(text);
        substring = ByteChanger.getNextValue(text);
        intendedSpeed = Integer.parseInt(substring);

        text = ByteChanger.incrementString(text);
        substring = ByteChanger.getNextValue(text);
        instance = Integer.parseInt(substring);

        text = ByteChanger.incrementString(text);
        return text;
    }
}